package assignment.ton.def;


import java.awt.Color;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.Vector;

import javax.swing.JFileChooser;
import javax.swing.filechooser.FileNameExtensionFilter;

import assignment.ton.gui.MainFrame;
/**
 * A class that stores a history and is responsible for saving and loading
 * @author Dean Allen (with much help in coding and problem solving of Tim)
 *
 */
public class History {
	private Vector<byte[]> history;
	private int historyIndex;
	private ByteArrayInputStream bis;
	private ObjectInputStream in;
	private ByteArrayOutputStream bos;
	private ObjectOutputStream out;
	private MainFrame mainFrame;
	private Class c;
	public History(MainFrame mF) {
		mainFrame = mF;
		history = new Vector<byte[]>();
		historyIndex = 0;
	}
	/**
	 * Called whenever main frame action changes
	 */
	public void changeOccured(){
		c = mainFrame.getSelected();
		addToHistory(c);
	}
	/**
	 * Goes one back in the history vector gets the class at that
	 * Then finds class with that name deletes it and replaces it by the other one
	 */
	public void undo(){
		System.out.println("Calling undo, index: "+historyIndex+", size: "+history.size());
		if(historyIndex > 0) historyIndex--;
		if(getClassAt(historyIndex)==null){ return; }
		ArrayList<Class> classList = mainFrame.getDrawPanel().getClasses();
		for(Class c: classList){
			if(c.getName().equals(getClassAt(historyIndex).getName())){
				classList.remove(c);
				classList.add(getClassAt(historyIndex));
			}
		}
		mainFrame.getDrawPanel().repaint();
	}
	/**
	 * Goes one forward in the history vector gets the class at that
	 * Then finds class with that name deletes it and replaces it by the other one
	 */
	public void redo(){
			System.out.println("Calling redo, index: "+historyIndex+", size: "+history.size());
			if(historyIndex< history.size()) historyIndex++;
			else{historyIndex = history.size()-1;
			}
			if(getClassAt(historyIndex)==null){ return; }
			ArrayList<Class> classList = mainFrame.getDrawPanel().getClasses();
			for(Class c: classList){
				if(c.getName().equals(getClassAt(historyIndex).getName())){
					classList.remove(c);
					classList.add(getClassAt(historyIndex));
				}
			}
			mainFrame.getDrawPanel().repaint();
	}
	/**
	 * Deletes all classes and resets history
	 */
	public void newStart(){
		if(Util.areYouSure("Doing this will delete everything currently loaded")){
			mainFrame.isSelected(null);
			mainFrame.setAction(Action.NONE);
			mainFrame.getDrawPanel().resetClassList();
			mainFrame.getDrawPanel().repaint();
			clear();
		}
	}
	/**
	 * Presents user with dialog and allows them to choose .ton files.
	 */
	public void open(){
		JFileChooser fc = new JFileChooser();
		fc.setFileFilter(new FileNameExtensionFilter("TON Jenerator Files", "ton"));
		fc.removeChoosableFileFilter(fc.getAcceptAllFileFilter());
		int returnVal = fc.showOpenDialog(fc);
		if (returnVal == JFileChooser.APPROVE_OPTION) {
			try {
				newStart();
				FileInputStream f = new FileInputStream(fc.getSelectedFile().getAbsolutePath());;
				ObjectInputStream in = new ObjectInputStream(f);
				Class clas = null;
				int j = in.readInt();
				for(int i = 0;i<j;i++){
					clas = (Class)in.readObject();
					if(clas!=null){
						mainFrame.getDrawPanel().addClassToList(clas);
					}
				}
				mainFrame.getDrawPanel().repaint();
				in.close();
				f.close();
			} catch (FileNotFoundException e1) {
				e1.printStackTrace();
			} catch (ClassNotFoundException e2) {
				e2.printStackTrace();
			} catch (IOException e3) {
				e3.printStackTrace();
			}
		}
	}
	/**
	 * Presents with dialog allows to save. If not .ton adds .ton
	 */
	public void save(){
		JFileChooser fc = new JFileChooser();
		fc.setFileFilter(new FileNameExtensionFilter("TON Jenerator Files", "ton"));
		fc.removeChoosableFileFilter(fc.getAcceptAllFileFilter());
		int returnVal = fc.showOpenDialog(mainFrame);
		if (returnVal == JFileChooser.APPROVE_OPTION) {
			File file = fc.getSelectedFile();
			String ext = file.toString().substring((int)file.toString().length()-4,(int)file.toString().length());
			if(ext.equals(".ton")==false){
				file = new File(file.toString()+".ton");
			}
			if(!file.exists()){ 
				if(Util.areYouSure("Create the file?","File doesn't exist")){
					try {
						file.createNewFile();
					} catch (IOException e) {
						Util.showError(mainFrame, "Could not create file");
						return;
					}
				}else{
					return;
				}
			}
			try {
				FileOutputStream fos = new FileOutputStream(file);
				ObjectOutputStream out = new ObjectOutputStream(fos);
				int i = mainFrame.getDrawPanel().getClasses().size();
				out.writeInt(i);
				if(mainFrame.getSelected()!=null){
					mainFrame.getSelected().setColor(new Color(0,205,255));
					mainFrame.isSelected(null);
				}
				for(Class h: mainFrame.getDrawPanel().getClasses()){
					out.writeObject(h);
				}
				out.close();
				fos.close();
				Util.showInfo(mainFrame, "Exporting successful");
			} catch (IOException e) {
				//Util.showError(mainFrame, e.printStackTrace());
				e.printStackTrace();
			}
		}else{
			Util.showError(mainFrame, "Choice not approved");
		}
	}
	/**
	 * @param i the history index
	 * @return the class at that index
	 */
	private Class getClassAt(int i){
		if(i>history.size()||i<0||history.size()<1){ return null; }
		try{
			bis = new ByteArrayInputStream(
					history.elementAt(i)
					);
			in = new ObjectInputStream(bis);
			Class tmp = (Class)in.readObject();
			return tmp;
		} catch(Exception e) {
			e.printStackTrace();
			return null;
		}
	}
	/**
	 * Saves a class state
	 * @param c the class to save
	 */
	public void addToHistory(Class c) {
		bos = new ByteArrayOutputStream();
		try {
			out = new ObjectOutputStream(bos);
			if(history.size() > 0) {
				for(int i=history.size()-1; i>historyIndex; i--) {
					System.out.println("Removing deprecated history at "+i+",size: "+history.size());
					history.remove(i);
				}
			}	
			out.writeObject(c);
			history.add(bos.toByteArray());
			historyIndex++;
			System.out.println("Adding to history, index: "+historyIndex+", size: "+history.size());
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	/**
	 * Clears history vector and sets index 0
	 */
	public void clear() {
		history.clear();
		historyIndex = 0;
	}
}